#ifndef __TYPE_LIST_H__
#define __TYPE_LIST_H__

namespace Boss
{

  namespace TL
  {

    template <typename H, typename T>
    struct TypeList
    {
      typedef H Head;
      typedef T Tail;
    };

    struct NullType
    {
    };

    namespace Internal
    {

      template <typename TList>
      struct CutNullTail
      {
        typedef TypeList
          <
            typename TList::Head,
            typename CutNullTail<typename TList::Tail>::List
          > List;
      };

      template <typename T>
      struct CutNullTail<TypeList<NullType, T> >
      {
        typedef NullType List;
      };

    }

    template
    <
      typename T0,
      typename T1 = NullType,
      typename T2 = NullType,
      typename T3 = NullType,
      typename T4 = NullType,
      typename T5 = NullType,
      typename T6 = NullType,
      typename T7 = NullType,
      typename T8 = NullType,
      typename T9 = NullType,
      typename T10 = NullType,
      typename T11 = NullType,
      typename T12 = NullType,
      typename T13 = NullType,
      typename T14 = NullType,
      typename T15 = NullType,
      typename T16 = NullType,
      typename T17 = NullType,
      typename T18 = NullType,
      typename T19 = NullType
    >
    class TypeListAdapter
    {
      typedef typename Internal::CutNullTail<
        TypeList<T0,
        TypeList<T1,
        TypeList<T2,
        TypeList<T3,
        TypeList<T4,
        TypeList<T5,
        TypeList<T6,
        TypeList<T7,
        TypeList<T8,
        TypeList<T9,
        TypeList<T10,
        TypeList<T11,
        TypeList<T12,
        TypeList<T13,
        TypeList<T14,
        TypeList<T15,
        TypeList<T16,
        TypeList<T17,
        TypeList<T18,
        TypeList<T19,
        NullType
        > > > > > > > > > > > > > > > > > > > >
      >::List NewTypeList;
    public:
      typedef typename NewTypeList::Head Head;
      typedef typename NewTypeList::Tail Tail;
    };

    template <typename T>
    struct ListLength
    {
      enum { Length = ListLength<typename T::Tail>::Length + 1 };
    };

    template <>
    struct ListLength<NullType>
    {
      enum { Length = 0 };
    };

    template <typename TFirst, typename TSecond, bool First>
    struct SelectType
    {
      typedef TFirst Type;
    };

    template <typename TFirst, typename TSecond>
    struct SelectType<TFirst, TSecond, false>
    {
      typedef TSecond Type;
    };

    template <typename TList, unsigned index>
    struct ListItem
    {
      typedef typename ListItem<typename TList::Tail, index - 1>::Type Type;
    };

    template <typename TList>
    struct ListItem<TList, 0>
    {
      typedef typename TList::Head Type;
    };

    template <unsigned index>
    struct ListItem<NullType, index>
    {
      typedef NullType Type;
    };

  }

}

#endif  // !__TYPE_LIST_H__
